package com.chuangjiangx.member.stored.ddd.domain.stardard;

import com.chuangjiangx.commons.JacksonUtils;
import com.chuangjiangx.commons.SpringContext;
import com.chuangjiangx.domain.shared.model.PayType;
import com.chuangjiangx.member.basic.ddd.domain.model.MbrAccount;
import com.chuangjiangx.member.basic.ddd.domain.model.MbrAccountRepository;
import com.chuangjiangx.member.basic.ddd.domain.model.Member;
import com.chuangjiangx.member.stored.ddd.domain.model.MbrOrderMirror;
import com.chuangjiangx.member.stored.ddd.domain.model.MbrStoredType;
import com.chuangjiangx.member.score.ddd.domain.model.MbrScoreType;
import com.chuangjiangx.domain.shared.model.PayEntry;
import com.chuangjiangx.member.stored.ddd.domain.model.MbrOrder;
import com.chuangjiangx.member.stored.ddd.domain.model.MbrOrderRepository;
import com.chuangjiangx.member.score.ddd.domain.model.MbrScoreGrandTotalRule;
import com.chuangjiangx.member.score.ddd.domain.repository.MbrScoreGrandTotalRuleRepository;
import com.chuangjiangx.member.stored.ddd.domain.event.MbrPaySuccessEvent;
import com.chuangjiangx.member.stored.ddd.domain.model.MbrOrderStatus;
import com.chuangjiangx.member.stored.ddd.domain.model.MbrOrderType;
import com.chuangjiangx.member.stored.ddd.domain.AbstractMbrPayment;
import com.chuangjiangx.member.stored.ddd.domain.MbrPaymentConstant;
import com.chuangjiangx.member.common.utils.MbrKeyManager;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;



/**
 * @author cj-ch
 * @date 2018/4/6 下午1:10
 */
public class StandardMbrPayment extends AbstractMbrPayment {
    protected static volatile Boolean inited = false;
    private static MbrOrderRepository mbrOrderRepository;
    private static MbrAccountRepository mbrAccountRepository;
    private static MbrScoreGrandTotalRuleRepository mbrScoreGrandTotalRuleRepository;
    private static RedisTemplate redisTemplate;
    private static ObjectMapper objectMapper;

    public StandardMbrPayment(MbrPaymentContext paymentContext) {
        super(paymentContext);
        andAfterPayment(paySuccessAfter());
        init();
    }

    private void init(){
        if(!inited){
            synchronized (StandardMbrPayment.class){
                if(!inited){
                    mbrOrderRepository = SpringContext.getBean(MbrOrderRepository.class);
                    mbrAccountRepository = SpringContext.getBean(MbrAccountRepository.class);
                    mbrScoreGrandTotalRuleRepository = SpringContext.getBean(MbrScoreGrandTotalRuleRepository.class);
                    redisTemplate = SpringContext.getBean("redisTemplate");
                    objectMapper = SpringContext.getBean("objectMapper");
                    inited = true;
                }
            }
        }
    }



    @Override
    protected MbrPaymentResult pay() {

        MbrPaymentResult result = new MbrPaymentResult();
        MbrOrder mbrOrder = paymentContext.getMbrOrder();
        MbrAccount mbrAccount = paymentContext.getMbrAccount();
        Member member = paymentContext.getMember();
        //账户扣除金额
        mbrAccount.changeMoney(mbrOrder.getPaidAmount(), MbrStoredType.CONSUMER);

        result.setResultCode(MbrPaymentConstant.SUCCESS);
        //客户端的支付方式相对于后端的PayEntry
        result.setPayType(mbrOrder.getPayEntry().value);
        result.setPayTerminal(mbrOrder.getPayTerminal().code);
        result.setPayStatus(MbrOrderStatus.PAID.value);
        result.setOrderNumber(mbrOrder.getOrderNumber());
        result.setPayTime(new Date());
        result.setTotalFee(mbrOrder.getOrderAmount());
        result.setRealPayFee(mbrOrder.getPaidAmount());
        result.setDiscountFee(mbrOrder.getDiscountAmount());
        result.setMemberId(member.getId().getId());
        result.setMobile(member.getMobile());
        //设置默认获得的积分
        result.setScore(0L);
        MbrScoreGrandTotalRule mbrScoreGrandTotalRule = paymentContext.getMbrScoreGrandTotalRule();
        if(Objects.equals(MbrOrderType.CONSUME,mbrOrder.getType())){
            //判断商户是否设置了积分累计规则并且客户实际消费金额是否大于0
            if(mbrScoreGrandTotalRule != null && mbrOrder.getPaidAmount().compareTo(BigDecimal.ZERO) >0){
                //设置本次积分
                Long score = mbrScoreGrandTotalRule.calcObtainScore(mbrOrder.getPaidAmount());
                result.setScore(score);
                //账户增加积分
                mbrAccount.changeScore(score,MbrScoreType.CONSUMER);
            }
        }
        result.setAvailableBalance(mbrAccount.getAvailableBalance());
        result.setAvailableScore(mbrAccount.getAvailableScore());

        mbrOrder.setPaidTime(new Date());
        mbrOrder.changeStatus(MbrOrderStatus.PAID);

        //持久化订单
        if(mbrOrder.getId() == null){
            mbrOrderRepository.save(mbrOrder);
        }else{
            mbrOrderRepository.update(mbrOrder);
        }
        result.setOrderId(mbrOrder.getId().getId());

        //把订单存储到redis,5分钟
        MbrOrderMirror mbrOrderMirror = MbrOrderMirror.of(mbrOrder);
        redisTemplate.opsForValue()
                .set(
                        MbrKeyManager.MBR_ORDER_ID_KEY+mbrOrderMirror.getId(),
                        JacksonUtils.toJson(objectMapper,mbrOrderMirror),
                        5,TimeUnit.MINUTES);
        return result;
    }





    /**
     * 储值\积分业务处理
     * @return
     */
    private BiConsumer<MbrPaymentContext,MbrPaymentResult> paySuccessAfter() {
        return (context,mbrPayResult) -> {
            if(mbrPayResult.isPaySuccess()){
                MbrOrder mbrOrder = paymentContext.getMbrOrder();
                Member member = paymentContext.getMember();

                MbrPaySuccessEvent mbrPaySuccessEvent = new MbrPaySuccessEvent.MbrPaySuccessEventBuild()
                        .setAmount(mbrOrder.getOrderAmount())
                        .setRealPayAmount(mbrOrder.getPaidAmount())
                        .setMbrHasCouponId(null != mbrOrder.getMbrHasCouponId() ? mbrOrder.getMbrHasCouponId().getId() : null)
                        .setMbrOrderId(mbrOrder.getId().getId())
                        .setMemberId(member.getId().getId())
                        .setMerchantId(mbrOrder.getMerchantId().getId())
                        .setMerchantUserId(mbrOrder.getMerchantUserId())
                        .setPayChannelId(15)
                        .setPayEntry(PayEntry.MSCARDPAY)
                        .setPayType(mbrOrder.getPayType())
                        .setPayTerminal(mbrOrder.getPayTerminal())
                        .setStoreId(mbrOrder.getStoreId())
                        .setStoreUserId(mbrOrder.getStoreUserId())
                        // TODO
                        .setMerchantAddress("")
                        .setStoreAddress("")
                        .build();

                redisTemplate.convertAndSend("mbr_pay_success",JacksonUtils.toJson(objectMapper,mbrPaySuccessEvent));
                if(Objects.equals(PayType.SCAN_PAY,mbrOrder.getPayType())){
                    redisTemplate.convertAndSend("stored-scan-pay", JacksonUtils.toJson(objectMapper,mbrPayResult));

                }
            }

        };
    }
}
